﻿using System.IdentityModel.Tokens.Jwt;
using System.Text;
using KL.Core.Common.MyOptions;
using KL.Standard.Model.Infrastructure;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;

namespace KL.Core.Extensions.Auth
{
    public static class JwtSetup
    {
        /// <summary>
        /// JWT认证
        /// </summary>
        /// <param name="services"></param>
        /// <param name="config"></param>
        /// <exception cref="ArgumentNullException"></exception>
        public static void AddAuthentication_JWTSetup(this IServiceCollection services, JwtConfigOptions config)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));


            //var symmetricKeyAsBase64 = config.securityKey;
            // var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
            // var signingKey = new SymmetricSecurityKey(keyByteArray);
            // var Issuer = config.issuser;
            // var Audience = config.audience;

            // var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            // 令牌验证参数
            var tokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.securityKey)),
                ValidateIssuer = true,
                ValidIssuer = config.issuser,//发行人
                ValidateAudience = true,
                ValidAudience =  config.audience,//订阅人
                ValidateLifetime = false
                // ValidateLifetime = true,//是否验证Token有效期，使用当前时间与Token的Claims中的NotBefore和Expires对比  当设置exp和nbf时有效 同时启用ClockSkew
                // ClockSkew = TimeSpan.FromSeconds(30),//注意这是缓冲过期时间，总的有效时间等于这个时间加上jwt的过期时间，如果不配置，默认是5分钟
                // RequireExpirationTime = true,// 是否要求Token的Claims中必须包含Expires
            };

            // 开启Bearer认证
            services.AddAuthentication(o =>
            {
                o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                //o.DefaultChallengeScheme = nameof(ApiResponseHandler);
                //o.DefaultForbidScheme = nameof(ApiResponseHandler);
            })//;
            //添加JwtBearer服务
            .AddJwtBearer(o =>
            {
                o.TokenValidationParameters = tokenValidationParameters;
                o.Events = new JwtBearerEvents
                {
                    OnChallenge = context =>
                    {
                        //3.所有失败时 返回调用放时的触发
                        //此处代码为终止.Net Core默认的返回类型和数据结果，这个很重要哦，必须
                        context.HandleResponse();
                        var errMsg = context.ErrorDescription ?? "认证缺失或者认证过期，请重新登录";
                        //var errMsg = "认证缺失或者认证过期，请重新登录";
                        
                        //自定义自己想要返回的数据结果，我这里要返回的是Json对象，通过引用Newtonsoft.Json库进行转换
                        var payload = JsonConvert.SerializeObject(
                            new BaseResult<string> { success = false, errCode = "403", error = errMsg });
                        //自定义返回的数据类型
                        context.Response.ContentType = "application/json";
                        //自定义返回状态码，默认为401 我这里改成 200
                        context.Response.StatusCode = StatusCodes.Status200OK;
                        //context.Response.StatusCode = StatusCodes.Status403Forbidden;
                        //输出Json数据结果
                        context.Response.WriteAsync(payload);
                        return Task.FromResult(0);
                    },
                    OnForbidden = context =>
                    {
                        
                        return Task.CompletedTask;
                    },
                    OnAuthenticationFailed = context =>
                    {
                        //1. 验证失败时
                        //2. 调用自定义策略来授权
                        var authorizationStr = string.Empty;
                        //if (context.Request.Headers["Authorization"] != null)
                        //    authorizationStr = context.Request.Headers["Authorization"].ToString();
                        var token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                        var jwtToken = (new JwtSecurityTokenHandler()).ReadJwtToken(token);
                
                        // if (jwtToken.Issuer != Issuer)
                        // {
                        //     context.Response.Headers.TryAdd("Token-Error", "Issuer-Wrong!");
                        // }
                        //
                        // if (jwtToken.Audiences.FirstOrDefault() != Audience)
                        // {
                        //     context.Response.Headers.TryAdd("Token-Error", "Audience-Wrong!");
                        // }
                
                
                        // 如果过期，则把<是否过期>添加到，返回头信息中
                        if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
                        {
                            context.Response.Headers.TryAdd("Token-Error", "Token-Expired");
                           
                        }
                
                        return Task.CompletedTask;
                    }
                };
            });
            //.AddScheme<AuthenticationSchemeOptions, ApiResponseHandler>(nameof(ApiResponseHandler), o => { });

        }
    }
}
